package physics;

import java.util.HashMap;
import physics.globalforce.Wall;


/**
 * Singleton that provides and maintains state of environmental forces.
 *
 * @author Kevin Gao, Connor Gordon
 *
 */
public final class EnvironmentSingleton {
    /**
     * Enumeration of all types of environmental forces.
     */
    public enum EnvironmentalForce {
        /**
         * Global gravitational force.
         */
        GRAVITY,
        /**
         * Air viscosity (resistance force).
         */
        VISCOSITY,
        /**
         * Gravitational force relative to any given assemblies center of mass.
         */
        CENTERMASS,
        /**
         * A wall force.
         */
        WALL
    }

    /**
     * Map that contains the state of which environmental forces are turned on.
     */
    private static HashMap<EnvironmentalForce, Boolean> ourEnvironmentalForces;

    /**
     * Singleton instance for environment state.
     */
    private static EnvironmentSingleton ourInstance = null;

    /**
     * Default constructor should do nothing.
     */
    private EnvironmentSingleton() {
    }

    /**
     * Retrieves the EnvironmentSingleton instance. Lazily instantiate a new
     * singleton upon calling.
     *
     * @return EnvironmentSingleton instance
     */
    public static synchronized EnvironmentSingleton getInstance() {
        if (ourInstance == null) {
            ourInstance = new EnvironmentSingleton();
            // Instantiate map with
            ourEnvironmentalForces = new HashMap<EnvironmentalForce, Boolean>();
            for (EnvironmentalForce ef : EnvironmentalForce.values()) {
                ourEnvironmentalForces.put(ef, true);
            }
        }
        return ourInstance;
    }

    /**
     * Get the on/off state of an environmental force.
     *
     * @param ef EnvironmentalForce in question
     * @return true if on, false if off
     */
    public boolean getForceState(final EnvironmentalForce ef) {
        return ourEnvironmentalForces.get(ef).booleanValue();
    }

    /**
     * Sets the state of an environmental force.
     *
     * @param ef EnvironmentalForce state to be changed
     * @param value Boolean value to set state to
     */
    public void setForceState(final EnvironmentalForce ef,
            final boolean value) {
        ourEnvironmentalForces.put(ef, Boolean.valueOf(value));
    }

    /**
     * Toggles the state of an environmental force.
     *
     * @param ef EnvironmentalForce state to be changed
     */
    public void toggleForceState(final EnvironmentalForce ef) {
        setForceState(ef, !getForceState(ef));
    }

    /**
     * Returns an array of strings, with each string representing the status of
     * a force.
     *
     * @return Array of status strings
     */
    public String[] getStateToPrint() {
        String[] state = {
                String.format("GRAVITY: %s",
                        getForceState(EnvironmentalForce.GRAVITY)),
                String.format("VISCOSITY: %s",
                        getForceState(EnvironmentalForce.VISCOSITY)),
                String.format("CENTER_OF_MASS: %s",
                        getForceState(EnvironmentalForce.CENTERMASS)),
                String.format("WALLS: %s (%d) [%s, %s, %s, %s]",
                        getForceState(EnvironmentalForce.WALL),
                        Wall.getOffset(),
                        Wall.isWallEnabled(Wall.TOP_WALL),
                        Wall.isWallEnabled(Wall.RIGHT_WALL),
                        Wall.isWallEnabled(Wall.BOTTOM_WALL),
                        Wall.isWallEnabled(Wall.LEFT_WALL)) };
        return state;
    }

}
